Skip to content

refactor(examples): drop the inert root title from six catalog dashboards - #7634

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-7624-catalog-root-title
Sep 4, 2026
Merged

refactor(examples): drop the inert root title from six catalog dashboards#7634
os-sam merged 2 commits into
mainfrom
claude/issue-7624-catalog-root-title

Conversation

@os-sam

@os-sam os-sam commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Fixes #7624

Deletes the root title key from the six filtered-* entries under
examples/schema-catalog/src/schemas/plugin-dashboard/, and pins that it cannot
come back.

Disposition was ruled by PM on the card (option 2, delete). Renaming to label
was rejected there and is not done here: none of the six declares header, and
DashboardRenderer gates its whole header section on header being declared
(objectui#5812), so renaming would give six shipped examples a header they have
never had — a feature, not a cleanup.

Premise, re-verified on this branch (not inherited)

Every tracked JSON file parsed structurally, not grepped: 627 files,
9 dashboard-shaped nodes (a node with a widgets array), 6 carrying a
root title — exactly the six named on the card, all still at the file root.

One refinement to the card's denominator: strict JSON.parse refuses 83 of
the 627 (they are JSONC tsconfig*.json files with comments and trailing
commas). A second pass stripped comments and re-parsed all 83 — 0 additional
dashboard-shaped nodes
, so the "627" figure survives, now with the whole
denominator actually parsed rather than 544 of it.

The label control is still DARK, and is reported as such. Zero of the 627
author a root label on a dashboard node, so the probe cannot discriminate
title from label; what it does demonstrate is that it reaches these nodes at
all — it enumerated all 9 with their key sets, including the 3 without title.
That distinction is preserved, not upgraded.

No catalog regeneration is owed — verified, not assumed.
scripts/regenerate-catalog-index.py reads curated metadata only from
src/catalog-meta.json and embeds each schema by import reference, never by
inlining its content. Proven by running the repo's own tooling: the case
the checked-in index.ts matches its generator in
scripts/__tests__/catalog-index-regenerable-4633.test.ts (which shells the
generator with --check against the real tree) passes on this branch, and
src/index.ts is unchanged.

"No visible change" as a measurement, not a sentence

All 9 plugin-dashboard catalog entries were rendered through the real
SchemaRenderer, exactly as the docs gallery renders them, before and after
the deletion:

observable before after
h2 elements across all 9 entries 0 0
header band col-span-full mb-4 occurrences 0 0
the six root-title strings in rendered output 2 2

The probe is LIT, which is what makes those zeros mean something. Those 2
occurrences are not a leak: they are widgets[0].title in
filtered-dashboard-dynamic-options.json, whose widget title happens to be the
same string as the deleted root title, rendered as a widget card's title
attribute plus its text node. So the probe demonstrably DOES detect title text
in the DOM when a live arm renders it — it finds the widget arm and not the
retired root arm. The two are told apart by RECEIVER, exactly as
DashboardRenderer's own comment says.

Raw rendered HTML was byte-compared too: 8 of 9 entries byte-identical
before-to-after. The 9th is not attributable to this change — a control run
of the identical tree twice, with no edit between, differs on 2 of the 9,
because the chart widgets sit behind a React.lazy boundary that resolves
nondeterministically (the AGENTS.md test-discipline phenomenon). Raw HTML bytes
are therefore a noisy probe and the stable observables above are the reading.

Why a pin for six deleted lines

Because nothing in the repo can notice the key coming back. Three receivers,
none of them red:

  • No renderer reads it — objectui#7509 (PR fix(dashboard): retire the dashboard-root title read on all five surfaces #7622) retired the root title
    arm in all five surfaces, so re-authoring it changes no pixel.
  • @object-ui/types still DECLARES itDashboardComponentSchema carries
    title?: string, and the Zod twin accepts and preserves it (measured:
    safeParse succeeds, data.title survives, since the twin does not declare
    title itself and BaseSchema is passthrough).
  • @objectstack/spec refuses it, but is not this corpus's validator
    DashboardSchema.safeParse reports the unrecognized-keys code listing
    type and title and naming the repair, and reports the same code listing
    only type once title is removed (that is how the reading was confirmed to
    be about title by name, not about the document generally). But these are
    ObjectUI SDUI component documents, not spec metadata documents: they fail that
    parse either way, on name, label, and the widgets' dataset/values. The
    spec's refusal never reaches them as a gate.

The pin carries a non-vacuity case, a counter-probe proving the assertion can
still fire, and a must-not-change case asserting the live widget.title keys
survive — so a blind sweep deleting every title in the corpus does not satisfy
it. It deliberately does not assert "zero label": label is the correct
spelling a later card should add, so pinning its absence would turn red on the
repair.

Ablation (the pin can fail): re-authoring "title": "Sales Overview" into
filtered-dashboard.json turns it RED with its intended message —
2 failed | 2 passed, the two controls staying green. The mutation was
confirmed on disk (root-title line count 0 to 1, non-empty git diff, and the
mutated file still parses as JSON) and the restore leg confirmed by git diff HEAD empty plus a blob hash equal to the HEAD blob.
A first ablation attempt was a MISRUN and is reported rather than discarded:
its editing one-liner ate the opening brace, so the pin failed to COLLECT
(invalid JSON) instead of failing its assertion. That red measured nothing; the
run above replaces it and now validates JSON parseability before believing any
red.

Verification

Run from the repo root, exit codes captured by redirect (never through a pipe),
all on final head dcf8fa8d:

  • pnpm exec vitest run examples/schema-catalog/ packages/plugin-dashboard/ scripts/__tests__/catalog-index-regenerable-4633.test.ts121 files, 2915 tests, all passed
  • pnpm exec turbo run type-check --concurrency=281 successful, 81 total
  • node scripts/check-changeset-presence.mjs — verdict verbatim: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. (7 files changed, 0 published source)
  • node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6240 tracked text file(s); skipped 85 binary).
  • node scripts/check-doc-component-types.mjs✅ Every documented component type is registered.
  • node scripts/check-governed-queue-guard.mjs --test on both changed paths — ✅ NOT GOVERNED

Lint is a declared narrowing, not a skip. The repo-wide pnpm lint is CI's
run; here it was narrowed to the diff and the narrowing is measured three ways:
(1) the population comes from eslint's own config, which declares only ts/tsx
globs — asked directly about one of the six JSON files it answers File ignored because no matching configuration was supplied, so the JSON edits are outside
its population entirely; (2) the file count comes from --format json: 1 file
linted, 0 errors, 0 warnings; (3) type-aware linting is not configured (no
project / projectService / parserOptions in eslint.config.js), so this
diff cannot move the verdict of any untouched file.

Housekeeping

Clause-② — no. Re-judged from the diff, not inherited: six JSON deletions in
examples/** plus one new test file. No published surface moves, no package
source changes, and no contract accept/reject behaviour is altered — the pin
only reads the corpus. needs:contract-review is therefore not owed.

Not governed — the guard's own answer on both changed paths.

Corroborates objectui#7623, does not overlap it. This branch's measurement
independently confirms that card's subject (DashboardComponentSchema.title
declared-but-unread). packages/types/** is held by that dispatch and is
untouched here.


Implemented by the domain:ui execution seat. Session reference, as prose so it
survives a body edit: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3

🤖 Generated with Claude Code

https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3


Generated by Claude Code

…boards

The six `filtered-*` entries under
`examples/schema-catalog/src/schemas/plugin-dashboard/` author a root `title`
that no arm reads. objectui#7509 (PR #7622) retired the last root `title`
reader across all five dashboard surfaces; `DashboardRenderer` reads
`schema.label` and gates the whole header section on `header` being declared
(objectui#5812). None of the six declares `header`, so they rendered no header
title before that retirement and render none after — the key was already inert,
and this makes the inertness total.

Renaming it to `label` was rejected: it would give six shipped examples a
header they have never had, which is a feature, not a cleanup.

Adds a pin, because nothing else in the repo can notice the key coming back:
no renderer reads it, `@object-ui/types` still declares `title?: string`, and
`@objectstack/spec` — which does refuse it by name — is not this corpus's
validator.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
The pin's rationale turns on all three receivers accepting the key. The Zod
half said "accepts it"; measured, it accepts AND preserves it (`safeParse`
succeeds and `data.title` survives), because the twin does not declare `title`
itself and `BaseSchema` is passthrough.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(examples): six catalog dashboards author a root title that no arm reads — and none rendered one even before #7509

2 participants